{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Numpy的结构化数组"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "一般情况下，Numpy中的数组都是同样的数据类型，比如int、float；  \n",
    "这也是Numpy性能高效的原因，在内存中紧凑存储，读取非常快；  \n",
    "\n",
    "但是Numpy也可以记录异构数组，比如下面的数据：  \n",
    "<table style=\"margin-left:0px\">\n",
    "    <tr>\n",
    "        <th>姓名</th>\n",
    "        <th>年龄</th>\n",
    "        <th>体重</th>\n",
    "    </tr>\n",
    "    <tr>\n",
    "        <td>小王</td>\n",
    "        <td>30</td>\n",
    "        <td>80.5</td>\n",
    "    </tr>\n",
    "    <tr>\n",
    "        <td>小李</td>\n",
    "        <td>28</td>\n",
    "        <td>70.3</td>\n",
    "    </tr>\n",
    "    <tr>\n",
    "        <td>小天</td>\n",
    "        <td>29</td>\n",
    "        <td>78.6</td>\n",
    "    </tr>\n",
    "</table>\n",
    "\n",
    "这就是本节要介绍的“Numpy结构化数组”特性；  "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "import numpy as np"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 1. 正常的Numpy数组的dtype值只有一个类型"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]), dtype('int32'))"
      ]
     },
     "execution_count": 2,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "arr = np.arange(10)\n",
    "arr, arr.dtype"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(array([[0.13813273, 0.69213455, 0.2869116 , 0.64065806],\n",
       "        [0.5972653 , 0.42803843, 0.84914465, 0.0502318 ],\n",
       "        [0.31351949, 0.87095862, 0.52867948, 0.83884873]]),\n",
       " dtype('float64'))"
      ]
     },
     "execution_count": 3,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "arr = np.random.rand(3, 4)\n",
    "arr, arr.dtype"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 2. 怎样使用Numpy表达异构数据"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "dtype([('name', '<U10'), ('age', '<i4'), ('weight', '<f8')])"
      ]
     },
     "execution_count": 4,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# dtype是可以单独定义成复合结构的\n",
    "my_dtype = np.dtype([('name', 'U10'), ('age', 'i4'), ('weight', 'f8')])\n",
    "my_dtype"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([('xiaowang', 30, 80.5), ('xiaoli', 28, 70.3),\n",
       "       ('xiaotian', 29, 78.6)],\n",
       "      dtype=[('name', '<U10'), ('age', '<i4'), ('weight', '<f8')])"
      ]
     },
     "execution_count": 5,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 构造异构数组\n",
    "my_arr = np.array(\n",
    "    [\n",
    "        ('xiaowang', 30, 80.5),\n",
    "        ('xiaoli', 28, 70.3),\n",
    "        ('xiaotian', 29, 78.6)\n",
    "    ], \n",
    "    dtype=my_dtype\n",
    ")\n",
    "my_arr"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 3. 针对异构数组的查询和操作"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 使用列表的方式查询一行"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "('xiaowang', 30, 80.5)"
      ]
     },
     "execution_count": 6,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "my_arr[0]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "('xiaotian', 29, 78.6)"
      ]
     },
     "execution_count": 7,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "my_arr[-1]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([('xiaowang', 30, 80.5), ('xiaoli', 28, 70.3)],\n",
       "      dtype=[('name', '<U10'), ('age', '<i4'), ('weight', '<f8')])"
      ]
     },
     "execution_count": 9,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "my_arr[0:2]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 使用字典的方式查询一列"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array(['xiaowang', 'xiaoli', 'xiaotian'], dtype='<U10')"
      ]
     },
     "execution_count": 10,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "my_arr['name']"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([30, 28, 29])"
      ]
     },
     "execution_count": 11,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "my_arr['age']"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 按条件查询"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([('xiaowang', 30, 80.5), ('xiaotian', 29, 78.6)],\n",
       "      dtype=[('name', '<U10'), ('age', '<i4'), ('weight', '<f8')])"
      ]
     },
     "execution_count": 12,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 按条件查询\n",
    "my_arr[my_arr[\"age\"] >= 29]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([('xiaowang', 30, 80.5)],\n",
       "      dtype=[('name', '<U10'), ('age', '<i4'), ('weight', '<f8')])"
      ]
     },
     "execution_count": 13,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 按多个条件查询\n",
    "my_arr[(my_arr[\"age\"] >= 29) & (my_arr[\"weight\"] > 80)]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 对单列做逐元素计算"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([30, 28, 29])"
      ]
     },
     "execution_count": 14,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "my_arr[\"age\"]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {},
   "outputs": [],
   "source": [
    "my_arr[\"age\"] += 1"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([31, 29, 30])"
      ]
     },
     "execution_count": 16,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "my_arr[\"age\"]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "最后的一言：  \n",
    "* 对于这种每列类型不同的“异构数据”，Pandas更擅长处理；\n",
    "* 但我们还要学习一下Numpy结构化数组，不一定会使用它，但要能读懂别人的代码"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.6"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
